#ifndef TEST_HASH_MAP_H_
#define TEST_HASH_MAP_H_
#include "protomsg_config.h"
#include <stdio.h>
#include <string>

namespace{
  typedef size_t hash_value;
  template< typename Str > struct defualt_hasher {
    hash_value operator() ( const Str& str ) const {
      typedef typename Str::value_type char_type;
      typedef typename Str::traits_type char_traits;
      const char_type* c_str = str.c_str();
      size_t len = char_traits::length(c_str);
      size_t h = len;
      size_t step = (len>>5)+1;
      size_t i;
      for (i=len; i>=step; i-=step)
        h = h ^ ((h<<5)+(h>>2)+(size_t)c_str[i-1]);
      return h;
    } 
  };
}

class ValueClass {
public:
  size_t a;
  ValueClass() {
    printf("CTor\n");
  }
  ValueClass( const ValueClass& is ) {
    a=is.a;
    printf("CCTor\n");
  }
  ~ValueClass() {
    printf("DTor\n");
  }
};

void test() {
  using protomsg::util::HashMap;
  using protomsg::util::FixedString ;
  typedef FixedString<48> AnsiStr;
  typedef HashMap<AnsiStr,ValueClass> VHashMap;

#if 0
  VHashMap hash_map_1;
  ValueClass vc;

  vc.a = 1;
  assert(hash_map_1.Insert( AnsiStr("A") , vc ));

  vc.a = 2;
  assert(hash_map_1.Insert( AnsiStr("B") , vc ));

  vc.a = 3;
  assert(hash_map_1.Insert( AnsiStr("C") , vc ));

  vc.a = 4;
  assert(hash_map_1.Insert( AnsiStr("D") , vc ));

  ::getchar();
  assert( hash_map_1.Query( AnsiStr("A") )->a == 1 && 
          hash_map_1.Query( AnsiStr("B") )->a == 2 &&
          hash_map_1.Query( AnsiStr("C") )->a == 3 &&
          hash_map_1.Query( AnsiStr("D") )->a == 4 );
  assert( hash_map_1.Query( AnsiStr("A") )->a == 1 && 
    hash_map_1.Query( AnsiStr("B") )->a == 2 &&
    hash_map_1.Query( AnsiStr("C") )->a == 3 &&
    hash_map_1.Query( AnsiStr("D") )->a == 4 );
  assert( hash_map_1.Query( AnsiStr("A") )->a == 1 && 
    hash_map_1.Query( AnsiStr("B") )->a == 2 &&
    hash_map_1.Query( AnsiStr("C") )->a == 3 &&
    hash_map_1.Query( AnsiStr("D") )->a == 4 );
  assert( hash_map_1.Query( AnsiStr("A") )->a == 1 && 
    hash_map_1.Query( AnsiStr("B") )->a == 2 &&
    hash_map_1.Query( AnsiStr("C") )->a == 3 &&
    hash_map_1.Query( AnsiStr("D") )->a == 4 );
  assert( hash_map_1.Query( AnsiStr("A") )->a == 1 && 
    hash_map_1.Query( AnsiStr("B") )->a == 2 &&
    hash_map_1.Query( AnsiStr("C") )->a == 3 &&
    hash_map_1.Query( AnsiStr("D") )->a == 4 );
  printf("ss");
#endif

#if 0
  // Using 1 to initialize the hash map will encounter error , we force 1 to be 2
  // 1 is the special case
  VHashMap hash_map_2(1);
  ValueClass vc2;
  vc2.a = 1;
  hash_map_2.Insert( AnsiStr("A") , vc2 );
  vc2.a = 2;
  hash_map_2.Insert( AnsiStr("B") , vc2 );
  vc2.a = 3;
  hash_map_2.Insert( AnsiStr("C") , vc2 );
  vc2.a = 4;
  hash_map_2.Insert( AnsiStr("D") , vc2 );

  vc2.a = 1;
  hash_map_2.Insert( AnsiStr("E") , vc2 );
  vc2.a = 2;
  hash_map_2.Insert( AnsiStr("ff") , vc2 );
  vc2.a = 3;
  hash_map_2.Insert( AnsiStr("gg") , vc2 );
  vc2.a = 4;
  hash_map_2.Insert( AnsiStr("sd") , vc2 );


  vc2.a = 1;
  hash_map_2.Insert( AnsiStr("h") , vc2 );
  vc2.a = 2;
  hash_map_2.Insert( AnsiStr("j") , vc2 );
  vc2.a = 3;
  hash_map_2.Insert( AnsiStr("i") , vc2 );
  vc2.a = 4;
  hash_map_2.Insert( AnsiStr("k") , vc2 );

  vc2.a = 1;
  hash_map_2.Insert( AnsiStr("sds") , vc2 );
  vc2.a = 2;
  hash_map_2.Insert( AnsiStr("sss") , vc2 );
  vc2.a = 3;
  hash_map_2.Insert( AnsiStr("sdkk") , vc2 );
  vc2.a = 4;
  hash_map_2.Insert( AnsiStr("a") , vc2 );
#endif 


#if 0
  VHashMap hash_map_2(1);
  ValueClass vc2;
  vc2.a = 1;
  hash_map_2.Insert( AnsiStr("A") , vc2 );
  vc2.a = 2;
  hash_map_2.Insert( AnsiStr("B") , vc2 );
  vc2.a = 3;
  hash_map_2.Insert( AnsiStr("C") , vc2 );
  vc2.a = 4;
  hash_map_2.Insert( AnsiStr("D") , vc2 );
  assert( hash_map_2.size() == 4 && !hash_map_2.empty() );

  assert( hash_map_2.Query( AnsiStr("A") )->a == 1 && 
          hash_map_2.Query( AnsiStr("B") )->a == 2 &&
          hash_map_2.Query( AnsiStr("C") )->a == 3 &&
          hash_map_2.Query( AnsiStr("D") )->a == 4 );
  assert( hash_map_2.Delete( AnsiStr("A")) && 
          hash_map_2.Delete( AnsiStr("B")) && 
          hash_map_2.Delete( AnsiStr("C")) && 
          hash_map_2.Delete( AnsiStr("D")) );

  assert( hash_map_2.size() ==0 && hash_map_2.empty() );
#endif 

  // testing the hash function ... 

  AnsiStr str1("A") , str2("B") ;
  typedef defualt_hasher<AnsiStr> Hasher;

  printf("%s\n",str1.c_str());
  printf("%d,%d\n",Hasher()(str1),Hasher()(str2));
  getchar();


}


#endif// TEST_HASH_MAP_H_